package in.co.codedoc.vsh;

import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;
import in.co.codedoc.ioc.IOCContainer;
import in.co.codedoc.json.JSONValue;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.PrintWriter;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

public class VelocityShell
{
	private static String usage = " --template-dir <directopry that holds velocity templates> [--help  - for usage]";

	public static void main(String[] args)
	{
		LongOpt[] opts 
			= new LongOpt[]
			  {
				new LongOpt("template-dir",LongOpt.REQUIRED_ARGUMENT,null,'t'),
				new LongOpt("help",LongOpt.NO_ARGUMENT,null,'h'),
			  }; 
		
		Getopt getopt = new Getopt(VelocityShell.class.getCanonicalName(),args,"?",opts,true);
		
		int c = -1;
		while((c = getopt.getopt()) != -1)
		{
			switch(c)
			{
			case '?':
			case 'h':
				System.err.println(usage);
				break;
			case 't':
				Velocity.addProperty
				(
					"file.resource.loader.path",
					getopt.getOptarg()
				);
				break;
			default:
				throw new RuntimeException(usage);
			}
		}
		
		for (String userdirective : userdirectives)
		{
			Velocity.addProperty
			(
				"userdirective",
				userdirective
			);
		}
		
		try
		{
			IOCContainer.ScanClasspath();
			IOCContainer.InitializeComponents();
			IOCContainer.StartComponents();

			Velocity.addProperty
			(
				"file.resource.loader.path",
				System.getProperty("java.io.tmpdir")
			);
			
			Velocity.addProperty
			(
				"file.resource.loader.path",
				System.getProperty("user.dir")
			);
			
			Velocity.init();
			VelocityContext context = new VelocityContext();

			BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
			String line = null;
			
			StringBuffer gatheredLines = null;

			String variableName = null;
			
			PrintWriter currentOutput = new PrintWriter(System.out);
			boolean closeCurrentOutput = false;
			
			while((line = in.readLine()) != null)
			{
				if(gatheredLines != null)
				{
					if(line.equals(ENIFED))
					{
						context.put
						(
							variableName,
							JSONValue.Decode(gatheredLines.toString())
						);
						
						gatheredLines = null;
					}
					else if(line.equals(CEXC))
					{
						File tempFile = File.createTempFile("inline-velocity-template", "vm");
						tempFile.deleteOnExit();
						
						FileWriter writer = new FileWriter(tempFile);
					
						writer.write(gatheredLines.toString());
						
						writer.flush();
						writer.close();
						
						Template template = Velocity.getTemplate(tempFile.getName());
			
						template.merge(context, currentOutput);
						currentOutput.flush();
						
						tempFile.delete();
						
						gatheredLines = null;
					}
					else
					{
						gatheredLines.append(line);
						gatheredLines.append('\n');
					}
				}
				else
				{
					//line -> command args
					String[] components = line.split(" ");
					
					if(components.length > 0)
					{
						if((components.length >= 2) && DEFINE.equals(components[0]))
						{
							if(components.length == 2)
							{
								variableName = components[1];
								gatheredLines = new StringBuffer();
							}
							else
							{
								StringBuffer payload = new StringBuffer();
								for(int i = 2; i< components.length;i++)
								{
									if(i > 2)
									{
										payload.append(' ');
									}
									payload.append(components[i]);
								}
								
								context.put
								(
									components[1],
									JSONValue.Decode(payload.toString())
								);
							}
						}
						else if((components.length == 1 || components.length == 2) && EXEC.equals(components[0]))
						{
							if(components.length == 1)
							{
								gatheredLines = new StringBuffer();
							}
							else
							{
								File templateFile = new File(components[1]);
																
								Template template = Velocity.getTemplate(templateFile.getName());
								
								template.merge(context, currentOutput);
								currentOutput.flush();			
							}
						}
						else if((components.length == 2) && UNDEFINE.equals(components[0]))
						{
							context.remove(components[1]);
						}
						else if((components.length == 2) && OUTFILE.equals(components[0]))
						{
							if((currentOutput != null) && closeCurrentOutput)
							{
								currentOutput.flush();
								currentOutput.close();
							}
							
							currentOutput = new PrintWriter(new FileWriter(components[1]));
						}
						else if((components.length == 1) && QUIT.equals(components[0]))
						{
							break;
						}
						else
						{
							Logger.logger.error("Ununderstood command:" + line + ". IGNORED.\n");
						}
					}
				}
			}

			if((currentOutput != null) && closeCurrentOutput)
			{
				currentOutput.flush();
				currentOutput.close();
			}
			
			IOCContainer.ShutdownComponents();
		}
		catch(Throwable th)
		{
			Logger.logger.error("Caught exception:" + th.getMessage(),th);
		}
	}
	
	private static final String DEFINE = "define";
	private static final String ENIFED = "enifed";
	private static final String EXEC = "exec";
	private static final String CEXC= "cexe";
	private static final String UNDEFINE = "undefine";
	private static final String OUTFILE = "outfile";
	private static final String QUIT = "quit";	

	private static String[] userdirectives = 
	{
		"in.co.codedoc.vsh.JSONForEach"
	};
	

}

